package ar.edu.isft189.pdfBox;


import java.io.IOException;
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
import org.apache.pdfbox.pdmodel.interactive.form.PDField;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDDocumentCatalog;
import org.apache.pdfbox.exceptions.COSVisitorException;
/**
 * PdfSetField permite tomar un formulario pdf, modificar sus campos (cargar
 * valores en los mismos) y grabar un nuevo pdf con los valores modificados
 * Se puede utilizar esta clase para setear los distintos campos del formulario
 * y luego visualizarlo y/o mandarlo a imprimir
 * Version modificada basada en clase SetField de los ejemplos publicados por 
 * Apache Org
 * Requiere Apache Org PDFBOX framework http://pdfbox.apache.org
 * 
 * @author Apache Org, G. Cherencio 
 * @version 1.0
 */
public final class PdfSetField {
    String pdfName = null;
    String pdfSaveAs = null;
    PDDocument pdf = null;
    PDDocumentCatalog docCatalog = null;
    PDAcroForm acroForm = null;
    
    /**
     * Crea objeto PdfSetField, luego debe indicar nombre de pdf
     * sobre el cual se va a trabajar
     */
    public PdfSetField() {}
    /**
     * Crea objeto PdfSetField, asume como new_[pdfName] al nuevo
     * formulario pdf a crear
     * 
     * @param pdfName nombre de archivo formulario pdf a utilizar
     */
    public PdfSetField(final String pdfName) {
        this(pdfName,"new_"+pdfName);
    }
    /**
     * Crea objeto PdfSetField
     * 
     * @param pdfName nombre de archivo formulario pdf a utilizar
     * @param newPdfName nombre del nuevo formulario pdf a crear
     */
    public PdfSetField(final String pdfName,final String newPdfName) {
        setPdfName(pdfName);
        setNewPdfName(newPdfName);
    }
    // SETTERS
    /**
     * Indica formulario pdf a utilizar
     * 
     * @param pdfstr nombre de archivo formulario pdf a utilizar
     */
    public void setPdfName(final String pdfstr) { 
        pdfName = pdfstr;
        try {
            pdf = PDDocument.load(JpdfForm.pdfFormDir + pdfName);        
            docCatalog = pdf.getDocumentCatalog();
            acroForm = docCatalog.getAcroForm();
        } catch(IOException ioe) {
            System.out.println("Error en PdfSetField, metodo setPdfName!!!! ==> " +  ioe.toString() );
            blank();
        }
    }
    /**
     * Indica formulario pdf a crear
     * 
     * @param pdf nombre de archivo formulario pdf nuevo a crear
     */
    public void setNewPdfName(final String pdf) { pdfSaveAs = JpdfForm.savePdfFormDir + pdf; }
    /**
     * Permite utilizar un objeto PdfSetField a partir de un objeto 
     * PDDocument previamente instanciado
     * 
     * @param p documento pdf 
     */
    public void setPdf(PDDocument p) { pdf = p; }
    /**
     * Carga el valor de un campo del formulario
     * 
     * @param fieldName nombre del campo 
     * @param fieldValue valor del campo 
     */
    public void setValue(final String fieldName,final String fieldValue) {
        if ( acroForm != null ) {
            try {
                PDField field = acroForm.getField(fieldName);                
                field.setValue( fieldValue );
            } catch(IOException ioe) {
                System.out.println("Error en PdfSetField.setValue => " + ioe.toString() );
            }
            catch(Exception e) {
                e.getStackTrace();
                e.printStackTrace();
                System.out.println("Error en PdfSetField.setValue => " + e.toString() );
            }
        }else{
            System.out.println("Error en PdfSetField.setValue acroForm NULO" );
        }
    }
    // GETTERS
    /**
     * Obtiene objeto PDDocument asociado
     * 
     * @return objeto PDDocument asociado
     */
    public PDDocument getPdf() { return pdf; }
    /**
     * Obtiene nombre de archivo pdf a utilizar
     * 
     * @return nombre de archivo pdf a utilizar
     */
    public String getPdfName() { return pdfName; }
    /**
     * Obtiene nombre de archivo pdf a crear
     * 
     * @return nombre de archivo pdf a crear
     */
    public String getNewPdfName() { return pdfSaveAs; }
    /**
     * Obtiene objeto PDField a partir de su nombre
     * 
     * @return objeto PDField representado por name
     */
    public PDField getField(final String name) { 
        if ( acroForm != null ) {
            try {
                return acroForm.getField(name);
            } catch(IOException ioe) {
            }
        }
        return null;
    }

    // CUSTOM
    /**
     * Crea un nuevo pdf a partir del actual
     * 
     * @return true si pudo grabar pdf como saveAs, sino devuelve false
     */
    public boolean saveAs(final String saveAs) {
        pdfSaveAs = saveAs;
        return save();
    }
    /**
     * Crea un nuevo pdf a partir del actual
     * 
     * @return true si pudo grabar pdf, sino devuelve false
     */
    public boolean save() {
        if ( pdf != null ) {
            try {
                if ( pdfSaveAs == null ) pdfSaveAs = "new_" + pdfName;
                pdf.save(pdfSaveAs);
            } catch(COSVisitorException cve) {
                return false;
            } catch(IOException ioe) {
                return false;
            }
        } else return false;
        return true;
    }
    /**
     * Cierra el objeto pdf actual y elimina referencias de todos los 
     * objetos internos que se requieren para realizar las operaciones (
     * excepto el nombre del nuevo archivo pdf creado).
     * Utilizar este metodo al finalizar el trabajo con este objeto. 
     * 
     * @return true si pudo cerrar pdf, sino devuelve false
     */
    public boolean close() {
        if ( pdf != null ) {
            try {
                pdf.close();
                blank();
            } catch(IOException ioe) {
                return false;
            }
        } else return false;
        return true;
    }
    
    // limpia las referencias a objetos que ya no se requieren
    private void blank() {
        pdf = null;
        pdfName = null;
        docCatalog = null;
        acroForm = null;
    }
}